package com.corpgovernment.organization.service;

import static com.corpgovernment.organization.constant.OrganizationResponseCodeEnum.BOOKING_RANGE_ADD_VALID_ORG_ID;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.corpgovernment.api.organization.dto.request.BookingRelation;
import com.corpgovernment.api.organization.enums.UserOrgRelationStatusEnum;
import com.corpgovernment.api.organization.model.bookingrelation.*;
import com.corpgovernment.api.organization.model.bookingrelation.BookingRange.BookingUser;
import com.corpgovernment.api.organization.model.org.GetOrgTreeResponse;
import com.corpgovernment.api.organization.model.user.employee.EmployeeOrgVo;
import com.corpgovernment.common.base.BaseUserInfo;
import com.corpgovernment.common.base.ResourceInfo;
import com.corpgovernment.common.common.CorpBusinessException;
import com.corpgovernment.common.enums.CardEnum;
import com.corpgovernment.common.enums.ExceptionCodeEnum;
import com.corpgovernment.common.operatelog.constant.OperateLogContant;
import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import com.corpgovernment.organization.entity.db.*;
import com.corpgovernment.organization.mapper.BookingRelationMapper;
import com.corpgovernment.organization.mapper.MbOrgInfoMapper;
import com.corpgovernment.organization.mapper.MbUserOrgRelationMapper;
import com.corpgovernment.organization.operatelog.service.enums.BookingRelationEnum;
import com.corpgovernment.organization.operatelog.service.pojo.BookingRelationPojo;
import com.corpgovernment.organization.service.impl.OrganizationInfoServiceImpl;
import com.corpgovernment.organization.util.JsonUtil;
import com.corpgovernment.organization.util.OrganizationUtil;
import com.corpgovernment.organization.util.PageUtil;
import com.corpgovernment.organization.vo.BookingRelationResponse;
import com.corpgovernment.redis.cache.RoleResourceManager;
import com.ctrip.corp.obt.generic.core.context.UserInfoContext;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.JsonUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.ctrip.corp.obt.shard.context.PageContext;
import com.ctrip.corp.obt.shard.sql.mybatis.interceptor.pagination.IPage;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.entity.Example.Criteria;

import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.corpgovernment.organization.constant.OrganizationResponseCodeEnum.BOOKING_RANGE_ADD_VALID_ORG_ID;

@Service
@Slf4j
public class BookingRelationService {
    @Autowired
    private BookingRelationMapper bookingRelationMapper;
    @Autowired
    private OrganizationInfoServiceImpl organizationInfoService;
    @Autowired
    private IOrganizationEmployeeService iOrganizationEmployeeService;
    @Autowired
    private IOrgUserIdCardService iOrgUserIdCardService;
    @Autowired
    private RoleResourceManager manager;
    @Autowired
    @Qualifier(value = "defaultThreadPoolExecutor")
    private ThreadPoolExecutor defaultThreadPoolExecutor;
    @Autowired
    private MbUserOrgRelationMapper userOrgRelationMapper;
    @Autowired
    private MbOrgInfoMapper orgInfoMapper;
    @Autowired
    private IOrganizationEmployeeService employeeService;

    public ListBRResp pageQuery(ListBRReq req) {
        // 获取所有的组织信息
        List<MbOrgInfo> mbOrgInfoList = organizationInfoService.listAll();
        // 根据req中的组织id查询此组织id所属末级公司的所有部门id
        List<String> orgIds = getOrgIds(req);
        if (CollectionUtils.isEmpty(orgIds)) {
            return new ListBRResp();
        }
        // 查询这些组织id下代订人uid和orgId
        IPage<MbBookingRelation> dataPage = PageContext.startPage(Optional.ofNullable(req.getPageNum()).orElse(1),
            Optional.ofNullable(req.getPageSize()).orElse(20),
            () -> bookingRelationMapper.pageQuery(req.getName(), orgIds));



        // 代订人信息
        List<MbBookingRelation> mbrList = dataPage.getRecords().stream()
            .filter(mbr -> StringUtils.isNotBlank(mbr.getUid()) && StringUtils.isNotBlank(mbr.getOrgId()))
            .collect(Collectors.toList());


        Map<String, MbOrgInfo> orgMap = mbOrgInfoList.stream().collect(Collectors.toMap(MbOrgInfo::getOrgId, p -> p));

        log.info("mbrList:{}", JsonUtils.toJsonString(mbrList));
        log.info("orgMap:{}", JsonUtils.toJsonString(orgMap));

        return buildPageQueryResponse(dataPage, mbrList, orgMap);
    }

    /**
     * 构建查询代订人信息列表响应
     */
    ListBRResp buildPageQueryResponse(IPage<MbBookingRelation> dataPage, List<MbBookingRelation> mbrList, Map<String, MbOrgInfo> orgMap) {
        ListBRResp resp = new ListBRResp();
        List<MbBookingRelationVo> mbrvList = mbrList.stream()
            .map(mbr -> buildBookingRelation(mbr, orgMap))
            .collect(Collectors.toList());
        resp.setData(mbrvList);
        resp.setTotalCount(dataPage.getTotal());
        resp.setPageNum((int) dataPage.getCurrent());
        resp.setPageSize((int) dataPage.getSize());
        resp.setTotalPage((int) dataPage.getPages());
        return resp;
    }

    /**
     * 构建代订信息
     */
    private MbBookingRelationVo buildBookingRelation(MbBookingRelation mbr, Map<String, MbOrgInfo> orgMap) {
        MbBookingRelationVo mbrv = new MbBookingRelationVo();
        mbrv.setUid(mbr.getUid());
        mbrv.setName(mbr.getName());


        mbrv.setOrgId(mbr.getOrgId());
        mbrv.setStatus(mbr.getStatus());
        mbrv.setBookForNonEmployee(mbr.getBookForNonEmployee());
        mbrv.setCreateTime(mbr.getDatachangeCreatetime());

        List<MbBookingRelation>  bookUidList = bookingRelationMapper.selectBookUidList(mbr.getUid(),mbr.getOrgId());
        int bookOrgIdSize = 0;
        int bookUidSize = 0;
        for (int i = 0; i < bookUidList.size(); i++) {
            MbBookingRelation item = bookUidList.get(i);
            if(StringUtils.isNotBlank(item.getBookUid())) {
                bookUidSize++;
                continue;
            }
            if(StringUtils.isNotBlank(item.getOrgId())){
                bookOrgIdSize++;
            }
        }
        mbrv.setBookOrgIdSize(bookOrgIdSize);
        mbrv.setBookUidSize(bookUidSize);
        List<String> orgPath = OrganizationUtil.findOrgTreeFromCurrentOrg(mbr.getOrgId(), orgMap).stream()
            .map(MbOrgInfo::getName)
            .collect(Collectors.toList());
        mbrv.setDepartment(orgPath);
        return mbrv;
    }

    private List<String> getOrgIds(ListBRReq req) {
        BaseUserInfo baseUserInfo = UserInfoContext.getContextParams(BaseUserInfo.class);
        if (!baseUserInfo.getDataPermissionControl()) {
            if (StringUtils.isBlank(req.getOrgId())){
                return Collections.emptyList();
            }

            return organizationInfoService.listRecentCompanyAllOrgIds(req.getOrgId());
        }
        ResourceInfo resource = manager.getResource(String.valueOf(baseUserInfo.getRoleId()), ResourceInfo.class);
        return resource.getDeptInfos().stream().map(ResourceInfo.DeptInfo::getOrgId).collect(Collectors.toList());
    }

    /**
     * 分页查询被代订人信息
     */
    public ListBookedUserResponse listBookedUser(ListBookedUserRequest req, StringJoiner sj) {
        String bookedName = Optional.ofNullable(req.getBookedUserName()).filter(StringUtils::isNotBlank).orElse(null);
        String bookedEmail = Optional.ofNullable(req.getBookedUserEmail()).filter(StringUtils::isNotBlank).orElse(null);
        String bookedPhone = Optional.ofNullable(req.getBookedUserMobilePhone())
            .filter(StringUtils::isNotBlank).orElse(null);

        List<String> bookedOrgIdList = Optional.ofNullable(req.getBookOrgIdList())
            .orElse(Collections.emptyList()).stream()
            .filter(StringUtils::isNotBlank).collect(Collectors.toList());

        int pageNum = Optional.ofNullable(req.getPageNum()).filter(x -> x > 0).orElse(1);
        int pageSize = Optional.ofNullable(req.getPageSize()).filter(x -> x > 0).orElse(50);

        // 查询代订范围
        BookingRange bookingRange = queryBookingRange(req.getUid(), req.getOrgId(), bookedOrgIdList, sj);
        if (bookingRange == null) {
            return buildListBookedUserResponse(Collections.emptyList(), Collections.emptyList(),
                Collections.emptyList(), pageNum, pageSize, sj);
        }

        // 设置要查询的被代订人
        List<BookingUser> bookingUsers = bookingRange.getBookingUsers();

        // 设置代订组织下的被代订人
        if (CollectionUtils.isNotEmpty(bookingRange.getBookingRange())) {
            List<BookingUser> bookingUserByOrgIds = userOrgRelationMapper.listByOrgIds(bookingRange.getBookingRange())
                .stream()
                .map(relation -> new BookingUser(relation.getUid(), relation.getOrgId()))
                .collect(Collectors.toList());

            sj.add("按组织代订查询出的被代订人：" + JsonUtils.toJsonString(bookingUserByOrgIds));
            bookingUsers.addAll(bookingUserByOrgIds);
        }
        bookingUsers = bookingUsers.stream().distinct().collect(Collectors.toList());
        sj.add("所有的被代订人：" + JsonUtils.toJsonString(bookingUsers));
        if (CollectionUtils.isEmpty(bookingUsers)){
            return buildListBookedUserResponse(Collections.emptyList(), Collections.emptyList(),
                Collections.emptyList(), pageNum, pageSize, sj);
        }

        // 查询被代订人的信息
        List<String> uidList = bookingUsers.stream()
            .map(BookingUser::getUid).distinct()
            .collect(Collectors.toList());

        // 查询被代订人的组织信息
        List<String> orgIdList = bookingUsers.stream()
            .map(BookingUser::getOrgId).distinct()
            .collect(Collectors.toList());
        List<MbOrgInfo> mbOrgInfoList = orgInfoMapper.listByOrgIds(orgIdList);
        sj.add("查询出的组织信息：" + JsonUtils.toJsonString(mbOrgInfoList));

        // 查询被代订人信息
        if (bookedName != null) {
            // 被代订人名不为空，因为要模糊查询，数据库加密了无法模糊查询，只能在代码里做
            List<MbOrgEmployeeInfo> employeeInfoList = employeeService.listByUids(uidList);
            sj.add("查询出的员工信息：" + JsonUtils.toJsonString(employeeInfoList));

            List<Predicate<MbOrgEmployeeInfo>> predicateList = new ArrayList<>();

            // 查询条件1：模糊匹配员工名
            predicateList.add(employee -> employee.getName() != null && employee.getName().contains(bookedName));

            // 查询条件2：精确匹配邮箱号
            if (bookedEmail != null) {
                predicateList.add(employee -> bookedEmail.equals(employee.getEmail()));
            }
            // 查询条件3：精确匹配电话号
            if (bookedPhone != null) {
                predicateList.add(employee -> bookedPhone.equals(employee.getMobilePhone()));
            }
            // 满足上述3个查询条件中任意一条的最终结果
            employeeInfoList = employeeInfoList.stream()
                .filter(employee -> predicateList.stream().anyMatch(predicate -> predicate.test(employee)))
                .collect(Collectors.toList());

            return buildListBookedUserResponse(employeeInfoList, mbOrgInfoList, bookingUsers, pageNum, pageSize, sj);
        } else {
            IPage<MbOrgEmployeeInfo> page =
                employeeService.pageByUidsAndAnyParam(uidList, bookedPhone, bookedEmail, pageNum, pageSize);
            sj.add("查询出的员工信息：" + JsonUtils.toJsonString(page.getRecords()));
            return buildListBookedUserResponse(page, mbOrgInfoList, bookingUsers, pageNum, sj);
        }
    }

    /**
     * 查询代订范围
     *
     * @param uid 代订人uid
     * @param orgId 代订人组织id
     * @param bookedOrgIds 被代订人组织id
     */
    private BookingRange queryBookingRange(String uid, String orgId, List<String> bookedOrgIds, StringJoiner sj) {

        sj.add("开始查询代订范围");

        Example example = new Example(MbBookingRelation.class);
        Criteria criteria = example.createCriteria()
            .andEqualTo("uid", uid)
            .andEqualTo("orgId", orgId)
            .andEqualTo("status","T");
        if (CollectionUtils.isNotEmpty(bookedOrgIds)) {
            criteria.andIn("bookOrgId", bookedOrgIds);
        }

        sj.add("查询代订范围参数 uid:" + uid);
        sj.add("查询代订范围参数 orgId:" + orgId);
        sj.add("查询代订范围参数 bookedOrgIds:" + JsonUtils.toJsonString(bookedOrgIds));

        List<MbBookingRelation> bookingRelations = bookingRelationMapper.selectByExample(example);

        sj.add("查询出的代订关系:" + JsonUtils.toJsonString(bookingRelations));

        if (CollectionUtils.isEmpty(bookingRelations)) {
            return null;
        }

        // 是否代订非员工
        Boolean bookForNonEmployee = bookingRelations.stream()
            .map(MbBookingRelation::getBookForNonEmployee).findFirst()
            .orElseThrow(() -> new IllegalArgumentException("未获取到是否代订非员工"));

        // 能代订的组织
        List<String> bookOrgIds = bookingRelations.stream()
            // 被代订人uid为空，说明是代订的组织
            .filter(bookingRelation -> StringUtils.isBlank(bookingRelation.getBookUid()))
            .map(MbBookingRelation::getBookOrgId)
            .filter(StringUtils::isNotBlank)
            .distinct()
            .collect(Collectors.toList());

        // 能代订的人
        List<BookingUser> bookUsers = bookingRelations.stream()
            // 被代订人uid不为空，说明是代订的人
            .filter(bookingRelation -> StringUtils.isNotBlank(bookingRelation.getBookUid()))
            .filter(bookingRelation -> StringUtils.isNotBlank(bookingRelation.getBookOrgId()))
            .map(bookingRelation -> new BookingUser(bookingRelation.getBookUid(), bookingRelation.getBookOrgId()))
            .collect(Collectors.toList());

        BookingRange bookingRange = new BookingRange();
        bookingRange.setBookForNonEmp(bookForNonEmployee);
        bookingRange.setBookingRange(bookOrgIds);
        bookingRange.setBookingUsers(bookUsers);

        sj.add("查询出的代订范围:" + JsonUtils.toJsonString(bookingRange));
        return bookingRange;
    }

    /**
     * 构建被代订人信息
     */
    private List<BookedUserInfo> buildBookedUserInfo(List<BookingUser> bookingUsers,
        List<MbOrgEmployeeInfo> employeeInfoList, List<MbOrgInfo> mbOrgInfoList, StringJoiner sj) {

        Map<String, MbOrgEmployeeInfo> employeeMap = employeeInfoList.stream()
            .collect(Collectors.toMap(MbOrgEmployeeInfo::getUid, x -> x, (x1, x2) -> x1));
        Map<String, MbOrgInfo> orgMap = mbOrgInfoList.stream()
            .collect(Collectors.toMap(MbOrgInfo::getOrgId, x -> x, (x1, x2) -> x1));

        List<BookedUserInfo> results = new ArrayList<>();
        for (BookingUser bookingUser : bookingUsers) {

            String uid = bookingUser.getUid();
            String orgId = bookingUser.getOrgId();

            MbOrgEmployeeInfo employeeInfo = employeeMap.get(uid);
            if (employeeInfo == null) {
                sj.add("未查询到用户信息，uid：" + uid);
                continue;
            }
            MbOrgInfo orgInfo = orgMap.get(orgId);
            if (orgInfo == null) {
                sj.add("未查询到组织信息，orgId：" + orgId);
                continue;
            }

            BookedUserInfo bookedUserInfo = new BookedUserInfo();
            bookedUserInfo.setUid(employeeInfo.getUid());
            bookedUserInfo.setOrgId(orgInfo.getOrgId());
            bookedUserInfo.setOrgName(orgInfo.getName());
            bookedUserInfo.setName(employeeInfo.getName());
            bookedUserInfo.setEmail(employeeInfo.getEmail());
            bookedUserInfo.setMobilePhone(employeeInfo.getMobilePhone());

            results.add(bookedUserInfo);
        }
        return results;
    }

    /**
     * 构建查询被代订人响应
     */
    private ListBookedUserResponse buildListBookedUserResponse(IPage<MbOrgEmployeeInfo> page,
        List<MbOrgInfo> mbOrgInfoList, List<BookingUser> bookingUsers, int pageNum, StringJoiner sj) {
        ListBookedUserResponse response = new ListBookedUserResponse();
        response.setPageNum(pageNum);
        response.setTotalCount((int)page.getTotal());
        response.setTotalPage((int)page.getPages());

        // 超过最大页码，直接返回
        if (pageNum > page.getPages()) {
            return response;
        }

        List<MbOrgEmployeeInfo> employeeInfoList = page.getRecords();

        response.setBookedUserInfoList(buildBookedUserInfo(bookingUsers, employeeInfoList, mbOrgInfoList, sj));

        return response;
    }

    /**
     * 构建查询被代订人响应
     */
    private ListBookedUserResponse buildListBookedUserResponse(List<MbOrgEmployeeInfo> employeeInfoList,
        List<MbOrgInfo> mbOrgInfoList, List<BookingUser> bookingUsers, int pageNum, int pageSize, StringJoiner sj) {
        ListBookedUserResponse response = new ListBookedUserResponse();

        int totalCount = employeeInfoList.size();
        int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;

        response.setPageNum(pageNum);
        response.setTotalCount(totalCount);
        response.setTotalPage(totalPage);

        // 超过最大页码，直接返回
        if (pageNum > totalPage) {
            return response;
        }

        // 分页返回
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, totalCount);
        employeeInfoList = employeeInfoList.subList(startIndex, endIndex);
        response.setBookedUserInfoList(buildBookedUserInfo(bookingUsers, employeeInfoList, mbOrgInfoList, sj));

        return response;
    }

    public BookingRelationPojo convert(ListBRReq request) {
        List<MbOrgInfo> mbOrgInfoList = organizationInfoService.listAll();
        List<String> orgIds = StringUtils.isBlank(request.getOrgId()) ? null : new ArrayList<>(organizationInfoService.listRecentCompanyAllDepartmentByOrgId(request.getOrgId()));
        if (orgIds != null) {
            orgIds.add(request.getOrgId());
        }
        IPage<MbBookingRelation> dataPage = PageContext.startPage(Optional.ofNullable(request.getPageNum()).orElse(1),
            Optional.ofNullable(request.getPageSize()).orElse(20));
        bookingRelationMapper.pageQuery(request.getName(), orgIds);

        /*Page<MbBookingRelation> dataPage =
                PageHelper.startPage(Optional.ofNullable(request.getPageNum()).orElse(1),
                        Optional.ofNullable(request.getPageSize()).orElse(20))
                        .doSelectPage(() -> bookingRelationMapper.pageQuery(request.getName(), orgIds));*/

        List<UidOrgIdEntry> uidOrgIdList = dataPage.getRecords().stream()
            .filter(mbr -> StringUtils.isNotBlank(mbr.getUid()) && StringUtils.isNotBlank(mbr.getOrgId()))
            .map(mbr -> new UidOrgIdEntry(mbr.getUid(), mbr.getOrgId())).collect(Collectors.toList());
        List<MbBookingRelation> mbrList = Collections.emptyList();
        if (CollectionUtils.isNotEmpty(uidOrgIdList)) {
            mbrList = bookingRelationMapper.selectBookingRange(uidOrgIdList);
        }
        List<MbBookingRelationVo> mbrvList = new ArrayList<>();
        Map<String, MbOrgInfo> orgMap = mbOrgInfoList.stream().collect(Collectors.toMap(MbOrgInfo::getOrgId, p -> p));
        for (MbBookingRelation mbr : mbrList) {
            MbBookingRelationVo mbrv = new MbBookingRelationVo();
            BeanUtils.copyProperties(mbr, mbrv);
            int index = mbrvList.indexOf(mbrv);
            if (index >= 0) {
                if (StringUtils.isNotBlank(mbr.getBookOrgId())) {
                    List<String> orgPath = OrganizationUtil.findOrgTreeFromCurrentOrg(mbr.getBookOrgId(), orgMap).stream().map(MbOrgInfo::getName).collect(Collectors.toList());
                    mbrvList.get(index).getOrderRange().add(orgPath);
                }
            } else {
                mbrvList.add(mbrv);
                mbrv.setOrderRange(new ArrayList<>());
                List<String> orgPath = OrganizationUtil.findOrgTreeFromCurrentOrg(mbr.getOrgId(), orgMap).stream().map(MbOrgInfo::getName).collect(Collectors.toList());
                mbrv.setDepartment(orgPath);
                mbrv.setCreateTime(mbr.getDatachangeCreatetime());
                if (StringUtils.isNotBlank(mbr.getBookOrgId())) {
                    orgPath = OrganizationUtil.findOrgTreeFromCurrentOrg(mbr.getBookOrgId(), orgMap).stream().map(MbOrgInfo::getName).collect(Collectors.toList());
                    mbrv.getOrderRange().add(orgPath);
                }
            }
        }
        mbrvList.sort(Comparator.comparing(MbBookingRelationVo::getCreateTime));
        BookingRelationPojo bookingRelationPojo = new BookingRelationPojo();
        if (CollectionUtils.isNotEmpty(mbrvList)) {
            MbBookingRelationVo mbBookingRelationVo = mbrvList.get(0);
            bookingRelationPojo.setName(mbBookingRelationVo.getName());
            String join = StringUtils.join(mbBookingRelationVo.getDepartment(), ">");
            bookingRelationPojo.setDepartment(join);
            Boolean bookForNonEmployee = mbBookingRelationVo.getBookForNonEmployee();
            String msg = "";
            if (bookForNonEmployee) {
                msg = OperateLogContant.BOOKINGRELATIONTURE;
            } else {
                msg = OperateLogContant.BOOKINGRELATIONFALSE;
            }
            bookingRelationPojo.setBookForNonEmployee(msg);

            String sign = "";
            if (BookingRelationEnum.T.getCode().equalsIgnoreCase(mbBookingRelationVo.getStatus())) {
                sign = BookingRelationEnum.T.getDesc();
            } else if (BookingRelationEnum.S.getCode().equalsIgnoreCase(mbBookingRelationVo.getStatus())) {
                sign = BookingRelationEnum.S.getDesc();
            } else if (BookingRelationEnum.D.getCode().equalsIgnoreCase(mbBookingRelationVo.getStatus())) {
                sign = BookingRelationEnum.D.getDesc();
            }
            bookingRelationPojo.setStatus(sign);
        }
        return bookingRelationPojo;
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchInsert(AddOrUpdateBRReq req) {
        if (CollectionUtils.isEmpty(req.getBookingRange())) {
            req.setBookingRange(Collections.singletonList(new UidOrgIdEntry()));
        }

        // 要新设置的代订范围
        List<MbBookingRelation> newBookingRelation = req.getBookingRange().stream()
            .map(bookingRange -> new MbBookingRelation(req.getUid(), req.getOrgId(), bookingRange.getOrgId(),
                bookingRange.getUid(), req.getBookForNonEmp()))
            .collect(Collectors.toList());

        // 校验不能同时代订人和组织
        verifyBookUidAndOrgId(newBookingRelation);

        deleteBookingRelation(req.getOrgId(), req.getUid());
        bookingRelationMapper.insertList(newBookingRelation);
    }

    public List<UidOrgIdEntry> checkConfig(CheckExistenceReq req) {
        return req.getUidOrgIdList().stream().filter(e -> {
            Example example = new Example(MbBookingRelation.class);
            example.createCriteria()
                .andEqualTo("uid", e.getUid())
                .andEqualTo("orgId", e.getOrgId())
                .andNotEqualTo("status", MbBookingRelationVo.STATUS_DELETED);
            return bookingRelationMapper.selectCountByExample(example) > 0;
        }).collect(Collectors.toList());
    }

    public List<BookingRelationResponse> listBookingRange(String orgId, String uid) {
        Example example = new Example(MbBookingRelation.class);
        example.createCriteria()
            .andEqualTo("uid", uid)
            .andEqualTo("orgId", orgId)
            .andNotEqualTo("status", MbBookingRelationVo.STATUS_DELETED);
        List<MbBookingRelation> bookingRelationList =  bookingRelationMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(bookingRelationList)) {
            return CollectionUtils.newArrayList();
        }

        List<BookingRelationResponse> relationResponseList = new ArrayList<>();

        List<String> bookOrgIdList = bookingRelationList.stream().map(MbBookingRelation::getBookOrgId)
                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<String, MbOrgInfo> orgInfoMap = CollectionUtils.newHashMap();
        if(CollectionUtil.isNotEmpty(bookOrgIdList)) {
            List<MbOrgInfo> orgInfoList = orgInfoMapper.listByOrgIds(bookOrgIdList);
            if(CollectionUtils.isNotEmpty(orgInfoList)) {
                orgInfoMap = orgInfoList.stream().collect(Collectors.toMap(MbOrgInfo::getOrgId, mbOrgInfo -> mbOrgInfo));
            }
        }

        List<String> bookUidList = bookingRelationList.stream().map(MbBookingRelation::getBookUid)
                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<String, MbOrgEmployeeInfo> employeeInfoMap = CollectionUtils.newHashMap();
        if(CollectionUtil.isNotEmpty(bookUidList)) {
            List<MbOrgEmployeeInfo> employeeInfoList = employeeService.listByUids(bookUidList);
            if(CollectionUtils.isNotEmpty(employeeInfoList)) {
                employeeInfoMap = employeeInfoList.stream().collect(Collectors.toMap(MbOrgEmployeeInfo::getUid, employeeInfo -> employeeInfo));
            }
        }
        Map<String, MbOrgEmployeeInfo> finalEmployeeInfoMap = employeeInfoMap;
        Map<String, MbOrgInfo> finalOrgInfoMap = orgInfoMap;
        bookingRelationList.forEach(bean->{
            BookingRelationResponse relationResponse = new BookingRelationResponse();
            relationResponse.setId(bean.getId());
            relationResponse.setUid(bean.getUid());
            relationResponse.setOrgId(bean.getOrgId());
            relationResponse.setStatus(bean.getStatus());
            relationResponse.setBookForNonEmployee(bean.getBookForNonEmployee());
            relationResponse.setDatachangeCreatetime(bean.getDatachangeCreatetime());
            relationResponse.setDatachangeLasttime(bean.getDatachangeLasttime());
            if(StringUtils.isNotBlank(bean.getBookUid())) {
                relationResponse.setBookUid(bean.getBookUid());
                relationResponse.setName(Objects.nonNull(finalEmployeeInfoMap.get(bean.getBookUid()))
                        ? finalEmployeeInfoMap.get(bean.getBookUid()).getName():null);
            }
            if(StringUtils.isNotBlank(bean.getBookOrgId())) {
                relationResponse.setBookOrgId(bean.getBookOrgId());
                relationResponse.setOrgName(Objects.nonNull(finalOrgInfoMap.get(bean.getBookOrgId()))
                        ? finalOrgInfoMap.get(bean.getBookOrgId()).getName():null);
                relationResponse.setOrgType(Objects.nonNull(finalOrgInfoMap.get(bean.getBookOrgId()))
                        ? finalOrgInfoMap.get(bean.getBookOrgId()).getOrgType():null);
            }
            relationResponseList.add(relationResponse);
        });
        return relationResponseList;
    }

    /**
     * 查询代订范围组织结构
     *
     * @param orgId 代订人组织id
     * @param uid   代订人uid
     */
    public List<GetOrgTreeResponse> listBookingRangeOrgTree(String orgId, String uid) {
        // 查询所有的组织关系
        Future<List<GetOrgTreeResponse>> orgTreeFeature = CompletableFuture.supplyAsync(
            () -> OrganizationUtil.listOrgTree(organizationInfoService.listAll(), null, true),
            defaultThreadPoolExecutor);
        // 查询此代订人代订范围内的被代订人组织id
        Future<Set<String>> bookedOrgIdsFuture = CompletableFuture.supplyAsync(
            () -> bookingRelationMapper.listBookRangeBookOrgId(uid, orgId), defaultThreadPoolExecutor);
        try {
            List<GetOrgTreeResponse> orgTrees = orgTreeFeature.get(10, TimeUnit.SECONDS);
            Set<String> bookedOrgIds = bookedOrgIdsFuture.get(10, TimeUnit.SECONDS);

            StringJoiner logBuilder = new StringJoiner(System.lineSeparator());
            logBuilder.add("组织树：" + JsonUtil.toJson(orgTrees));
            logBuilder.add("有被代订人的组织id：" + JsonUtil.toJson(bookedOrgIds));
            log.info(logBuilder.toString());

            removeNoneBookedUserOrg(orgTrees, bookedOrgIds);
            return orgTrees;
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 移除没有被代订人的组织
     */
    private void removeNoneBookedUserOrg(List<GetOrgTreeResponse> orgTrees, Set<String> bookedOrgIds) {
        Iterator<GetOrgTreeResponse> iterator = orgTrees.iterator();
        while (iterator.hasNext()) {
            GetOrgTreeResponse orgTree = iterator.next();
            // 子组织不为空则处理子组织
            if (!CollectionUtils.isEmpty(orgTree.getChildren())) {
                removeNoneBookedUserOrg(orgTree.getChildren(), bookedOrgIds);
            }
            if (CollectionUtils.isEmpty(orgTree.getChildren())) {
                // 子组织为空则设置为null
                orgTree.setChildren(null);
                // 当前组织没被代订人则移除父组织的子组织中的当前组织
                if (!bookedOrgIds.contains(orgTree.getOrgId())) {
                    iterator.remove();
                }
            }
        }
    }

    public void updateStatus(UidOrgIdEntry index, String status, List<String> expectStatuses) {
        Example example = new Example(MbBookingRelation.class);
        Example.Criteria c = example.createCriteria();
        c.andEqualTo("uid", index.getUid())
            .andIn("status", expectStatuses);
        if (StringUtils.isNotBlank(index.getOrgId())) {
            c.andEqualTo("orgId", index.getOrgId());
        }
        MbBookingRelation mbr = new MbBookingRelation();
        mbr.setStatus(status);
        bookingRelationMapper.updateByExampleSelective(mbr, example);
    }

    public void setBookForNonEmployee(UidOrgIdEntry index, boolean book4NonEmp) {
        Example example = new Example(MbBookingRelation.class);
        example.createCriteria().andEqualTo("uid", index.getUid())
            .andEqualTo("orgId", index.getOrgId())
            .andNotEqualTo("status", MbBookingRelationVo.STATUS_DELETED);
        MbBookingRelation mbr = new MbBookingRelation();
        mbr.setBookForNonEmployee(book4NonEmp);
        bookingRelationMapper.updateByExampleSelective(mbr, example);
    }

    /**
     * 查询前台用户某个角色下的代订范围
     *
     * @param orgId 当前员工隶属的组织ID
     * @return 该用户未配置代订范围时，返回null
     */
    public BookingRange queryBookingRangeByUidAndOrgId(String uid, String orgId) {
        Example example = new Example(MbBookingRelation.class);
        example.createCriteria().andEqualTo("uid", uid)
            .andEqualTo("orgId", orgId)
            .andEqualTo("status", MbBookingRelationVo.STATUS_ENABLE);
        BookingRange br = new BookingRange();
        List<MbBookingRelation> brs = bookingRelationMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(brs)) {
            return null;
        }
        br.setBookForNonEmp(brs.get(0).getBookForNonEmployee());

        List<String> bookOrgIds = brs.stream()
            .filter(item -> StringUtils.isBlank(item.getBookUid()) && StringUtils.isNotBlank(item.getBookOrgId()))
            .map(MbBookingRelation::getBookOrgId).collect(Collectors.toList());
        br.setBookingRange(bookOrgIds);

        List<BookingRange.BookingUser> bookingUsers = new ArrayList<>();
        //获取bookuid
        List<MbBookingRelation> bookingRelationUid = brs.stream().filter(item -> Objects.nonNull(item.getBookUid())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(bookingRelationUid)) {
            bookingRelationUid.forEach(item -> {
                BookingRange.BookingUser bookingUser = new BookingRange.BookingUser();
                bookingUser.setOrgId(item.getBookOrgId());
                bookingUser.setUid(item.getBookUid());
                bookingUsers.add(bookingUser);
            });
        }
        br.setBookingUsers(bookingUsers);
        return br;
    }

    @Transactional(rollbackFor = Exception.class)
    public void syncBookingRelation(BookingRelation bookingRelation) {

        if (StringUtils.isBlank(bookingRelation.getOrgId())) {
            throw new CorpBusinessException(ExceptionCodeEnum.Alert, "代订人组织为空");
        }
        if (StringUtils.isBlank(bookingRelation.getUid())) {
            throw new CorpBusinessException(ExceptionCodeEnum.Alert, "代订人ID为空");
        }
        if (CollectionUtils.isEmpty(bookingRelation.getBookingUsers())) {
            deleteBookingRelation(bookingRelation.getOrgId(), bookingRelation.getUid());
            return;
        }
        bookingRelation.getBookingUsers().forEach(item -> {
            if (StringUtils.isBlank(item.getOrgId())) {
                throw new CorpBusinessException(ExceptionCodeEnum.Alert, "被代订人组织为空");
            }
        });

        Example queryExample = new Example(MbBookingRelation.class);
        queryExample.createCriteria().andEqualTo("uid", bookingRelation.getUid())
            .andEqualTo("orgId", bookingRelation.getOrgId())
            .andEqualTo("status", MbBookingRelationVo.STATUS_ENABLE);
        List<MbBookingRelation> brs = bookingRelationMapper.selectByExample(queryExample);

        List<String> bookUidList = bookingRelation.getBookingUsers().stream().filter(item -> StringUtils.isNotBlank(item.getUid())).map(BookingRelation.BookingUser::getUid).collect(Collectors.toList());

        List<EmployeeOrgVo> employeeInfoByIds = null;
        if (CollectionUtils.isNotEmpty(bookUidList)) {
            employeeInfoByIds = iOrganizationEmployeeService.findEmployeeInfoByIds(bookUidList);
        }

        Map<String, EmployeeOrgVo> empMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(employeeInfoByIds)) {
            empMap = employeeInfoByIds.stream().filter(Objects::nonNull).collect(Collectors.toMap(EmployeeOrgVo::getUid, Function.identity(), (p1, p2) -> p1));
        }

        for (BookingRelation.BookingUser item : bookingRelation.getBookingUsers()) {
            if (StringUtils.isNotBlank(item.getUid()) && empMap.get(item.getUid()) == null) {
                continue;
            }
            MbBookingRelation mbr = new MbBookingRelation(bookingRelation.getUid(), bookingRelation.getOrgId(),
                item.getOrgId(), item.getUid(), bookingRelation.getBookForNonEmp());
            brs.add(mbr);
        }

        // 去除重复数据
        TreeSet<MbBookingRelation> assembles = brs.stream()
            .map(br -> new MbBookingRelation(br.getUid(), br.getOrgId(), br.getBookOrgId(), br.getBookUid(),
                br.getBookForNonEmployee()))
            .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator
                .comparing(item -> defaultIfBlank(item.getBookOrgId()) + defaultIfBlank(item.getBookUid())))));

        // 要删除的代订组织map
        Map<String, List<BookingRelation.BookingUser>> deleteMap = bookingRelation.getBookingUsers().stream()
            .filter(item -> Boolean.TRUE == item.getIsDelete()).collect(Collectors.groupingBy(item ->
                defaultIfBlank(item.getOrgId()) + defaultIfBlank(item.getUid())
            ));

        List<MbBookingRelation> insertResult = assembles.stream()
            .filter(br -> !deleteMap.containsKey(defaultIfBlank(br.getBookOrgId()) + defaultIfBlank(br.getBookUid())))
            .collect(Collectors.toList());

        // 校验不能同时代订人和组织
        verifyBookUidAndOrgId(insertResult);

        //先删除全部
        deleteBookingRelation(bookingRelation.getOrgId(), bookingRelation.getUid());
        if (CollectionUtils.isNotEmpty(insertResult)) {
            bookingRelationMapper.insertList(insertResult);
        }
    }

    /**
     * 校验不能同时代订人和组织
     */
    private void verifyBookUidAndOrgId(List<MbBookingRelation> brs) {
        Set<String> bookOrgIdSet = brs.stream()
            .filter(br -> StringUtils.isBlank(br.getBookUid()))
            .map(MbBookingRelation::getBookOrgId)
            .filter(StringUtils::isNotBlank)
            .collect(Collectors.toSet());

        for (MbBookingRelation br : brs) {
            // 代订的是人并且此人的组织也需要被代订
            if (StringUtils.isNotBlank(br.getBookUid()) && bookOrgIdSet.contains(br.getBookOrgId())) {
                throw new CorpBusinessException(BOOKING_RANGE_ADD_VALID_ORG_ID, br.getBookOrgId());
            }
        }
    }

    /**
     * 删除此代订人下的代订权限
     *
     * @param orgId 代订人组织id
     * @param uid 代订人uid
     */
    public void deleteBookingRelation(String orgId, String uid) {
        Example example = new Example(MbBookingRelation.class);
        example.createCriteria()
            .andEqualTo("uid", uid)
            .andEqualTo("orgId", orgId);
        MbBookingRelation mbr = new MbBookingRelation();
        mbr.setStatus(MbBookingRelationVo.STATUS_DELETED);
        bookingRelationMapper.updateByExampleSelective(mbr, example);
    }

    private String defaultIfBlank(String str) {
        return StringUtils.isBlank(str) ? "" : str;
    }


    /**
     * 查询被代订人列表
     *
     * @param uid
     * @param orgId
     * @return
     */
    public List<BookingRelation.BookingUser> queryBookingUsers(String uid, String orgId) {
        Example example = new Example(MbBookingRelation.class);
        example.createCriteria().andEqualTo("uid", uid)
            .andEqualTo("orgId", orgId)
            .andEqualTo("status", MbBookingRelationVo.STATUS_ENABLE);
        List<MbBookingRelation> brs = bookingRelationMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(brs)) {
            return null;
        }
        List<BookingRelation.BookingUser> bookingUsers = new ArrayList<>();
        //查询bookOrg下面得所有uid
        List<String> bookOrgIds = brs.stream().filter(item -> Objects.isNull(item.getBookUid())).map(MbBookingRelation::getBookOrgId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(bookOrgIds)) {
            List<MbOrgEmployeeInfo> bookOrgIdResultList = iOrganizationEmployeeService.listByNameAndOrgIds("", bookOrgIds, UserOrgRelationStatusEnum.NORMAL.getStatus(), null, null);
            if (!CollectionUtils.isEmpty(bookOrgIdResultList)) {
                bookOrgIdResultList.stream().forEach(item -> {
                    BookingRelation.BookingUser bookingUser = new BookingRelation.BookingUser();
                    bookingUser.setOrgId(item.getOrgId());
                    bookingUser.setUid(item.getUid());
                    bookingUsers.add(bookingUser);
                });
            }
        }

        //获取bookuid
        List<MbBookingRelation> bookingRelationUid = brs.stream().filter(item -> Objects.nonNull(item.getBookUid())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(bookingRelationUid)) {
            bookingRelationUid.stream().forEach(item -> {
                BookingRelation.BookingUser bookingUser = new BookingRelation.BookingUser();
                bookingUser.setOrgId(item.getBookOrgId());
                bookingUser.setUid(item.getBookUid());
                bookingUsers.add(bookingUser);
            });
        }

        return bookingUsers;
    }


    public BookingEmployeeResponse queryBookingEmployee(BookingEmployeeRequest request) {
        List<BookingRelation.BookingUser> bookingUsers = this.queryBookingUsers(request.getUid(), request.getOrgId());
        if (CollectionUtils.isEmpty(bookingUsers)) {
            return null;
        }
        List<String> uidList = bookingUsers.stream().map(BookingRelation.BookingUser::getUid).collect(Collectors.toList());
        //uidList.add(request.getUid());
        List<MbOrgEmployeeInfo> employeeInfos = iOrganizationEmployeeService.listByUids(uidList);
        if (StringUtils.isNotBlank(request.getUserName())) {
            employeeInfos = employeeInfos.stream().filter(item -> Objects.nonNull(item) && item.getName().indexOf(request.getUserName()) > -1).collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(employeeInfos)) {
            return null;
        }
        BookingEmployeeResponse employeeResponse = new BookingEmployeeResponse();
        List<BookingEmployeeResponse.BookingEmployee> employees = new ArrayList<>();
        List<MbOrgUserIdcard> mbOrgUserIdcards = iOrgUserIdCardService.batchFindByUids(employeeInfos.stream().map(MbOrgEmployeeInfo::getUid).collect(Collectors.toList()));
        Map<String, MbOrgUserIdcard> cardMap = mbOrgUserIdcards.stream().filter(item -> Objects.nonNull(item)).collect(Collectors.toMap(MbOrgUserIdcard::getEmployeeUid, Function.identity(), (v1, v2) -> {
            if ("1".equals(v1.getCardType())) {
                return v1;
            } else if ("1".equals(v2.getCardType())) {
                return v2;
            } else {
                return v1;
            }
        }));
        employeeInfos.stream().forEach(item -> {
            BookingEmployeeResponse.BookingEmployee bookingEmployee = new BookingEmployeeResponse.BookingEmployee();
            bookingEmployee.setUserName(item.getName());
            bookingEmployee.setAreaCode(item.getAreaCode());
            bookingEmployee.setMobilePhone(item.getMobilePhone());
            bookingEmployee.setUserType(request.getUid().equals(item.getUid()) ? "本人" : "员工");
            MbOrgUserIdcard mbOrgUserIdcard = cardMap.get(item.getUid());
            if (Objects.nonNull(mbOrgUserIdcard)) {
                bookingEmployee.setCardNo(mbOrgUserIdcard.getCardNo());
                bookingEmployee.setCardType(CardEnum.getByType(mbOrgUserIdcard.getCardType() == null ? "" : String.valueOf(mbOrgUserIdcard.getCardType())).getName());
            }
            employees.add(bookingEmployee);
        });

        PageUtil pageUtil = new PageUtil();
        List<BookingEmployeeResponse.BookingEmployee> pageList = pageUtil.startPage(employees, request.getPageNum(), request.getPageSize());
        employeeResponse.setBookingEmployees(pageList);
        employeeResponse.setPageNum(request.getPageNum());
        employeeResponse.setPageSize(request.getPageSize());
        employeeResponse.setTotalCount(employees.size());
        return employeeResponse;
    }

    public boolean deleteBookingRelationByUid(String uid) {
        Example example = new Example(MbBookingRelation.class);
        example.createCriteria().andEqualTo("uid", uid).orEqualTo("bookUid", uid);
        MbBookingRelation mbBookingRelation = new MbBookingRelation();
        mbBookingRelation.setStatus(MbBookingRelationVo.STATUS_DELETED);
        return bookingRelationMapper.updateByExampleSelective(mbBookingRelation, example) > 0;
    }
}
